package com.fs.model;

import com.fs.util.FATUtil;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.ImageView;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Setter
@Getter
/**
 *这里当作文件分配表，统筹磁盘（磁盘块里面有属性object字段指向文件或文件夹）、路径的存放
 * 相当于数据库表持久存储
 */
public class FAT {
    //下面四个代表着持久存储
    private DiskBlock[] diskBlocks;//磁盘块，申请128个,磁盘块中有属性指向文件或文件夹
    private Folder c;//初始文件夹;c盘，占用0 1号磁盘块
    private Path rootPath = new Path("C:", null);//C盘就是根路径，无父文件夹
    private List<Path> paths;//用于存放所有路径，包括c盘

    //private Map<Path, TreeItem<String>> pathMap;
    private transient ObservableList<File> openedFiles;
    //下面代表着映射到界面的数据存放
    //存储当前路径下的文件的首个磁盘块 ，也就是用来展现当前文件或文件夹的，每次有文件或文件夹变化的时候需要刷新initPresentBlockList（）
    private List<DiskBlock> presentBlockList;
    public FAT() {
        c = new Folder("C:", "root", 0, null);//创建C盘
        diskBlocks = new DiskBlock[128];//一共128块磁盘。
        diskBlocks[0] = new DiskBlock(0, FATUtil.END, FATUtil.DISK, c);//第二个是index,第三个是类型，第四个是文件夹。
        diskBlocks[0].setBegin(true);//设置开始标记
        diskBlocks[1] = new DiskBlock(1, FATUtil.END, FATUtil.DISK, c);//no是记录第几块磁盘号。这个也是C盘
        //第二个index是值
        for (int i = 2; i < 128; i++) {
            //初始化磁盘块号，磁盘块使用情况
            diskBlocks[i] = new DiskBlock(i, FATUtil.FREE, FATUtil.EMPTY, null);
            //初始化其他磁盘块，并且标记为可以使用的，类型为空。文件为空。
        }

        paths = new ArrayList<Path>();//路径数组；动态数组；
        paths.add(rootPath);
        c.setPath(rootPath);//c是文件夹，在此设置该文件架的路径。

        //初始化当前文件夹
        presentBlockList=new ArrayList<>();

        openedFiles = FXCollections.observableArrayList(new ArrayList<File>());
        //测试数据
//        testData();

    }





    public void testData(){
        Path path1 = new Path("C:\\文件夹1", rootPath);
        Path path2 = new Path("C:\\文件夹2", rootPath);
        rootPath.getChildren().add(path1);
        rootPath.getChildren().add(path2);
        this.paths.add(path1);
        this.paths.add(path2);
        //String folderName,String location,int diskNum,Folder parent
        Folder folder1 = new Folder("文件夹1", "C:", 2, c);
        Folder folder2 = new Folder("文件夹2", "C:", 3, c);
        //int no,int index,String type,Object object
        diskBlocks[2] = new DiskBlock(2, FATUtil.END, FATUtil.FOLDER, folder1);
        diskBlocks[2].setBegin(true);
        diskBlocks[3] = new DiskBlock(3, FATUtil.END, FATUtil.FOLDER, folder2);
        diskBlocks[3].setBegin(true);

        //文件  String fileName, String location, int diskNum, Folder parent
        File file1 = new File("文件1", "C:\\文件夹1", 4, folder1);
        File file2 = new File("文件2", "C:\\文件夹2", 5, folder2);
        diskBlocks[4]=new DiskBlock(4, FATUtil.END, FATUtil.FILE, file1);
        diskBlocks[4].setBegin(true);
        diskBlocks[5]=new DiskBlock(5, FATUtil.END, FATUtil.FILE, file2);
        diskBlocks[5].setBegin(true);

    }

    public void initPresentBlockList(String recentPath){
        this.presentBlockList.clear();
        this.presentBlockList.addAll(this.getBlockList(recentPath));
    }

    //返回指定路径下的所有文件夹或文件
    public List<DiskBlock> getBlockList(String path) {
        List<DiskBlock> bList = new ArrayList<DiskBlock>();
        for (int i = 2; i < diskBlocks.length; i++) {
            if (!diskBlocks[i].isFree()) {
                if (diskBlocks[i].getObject() instanceof Folder) {
                    if (((Folder) (diskBlocks[i].getObject())).getLocation().equals(path)
                            && diskBlocks[i].isBegin()) {
                        bList.add(diskBlocks[i]);
                    }
                }
            }
        }
        for (int i = 2; i < diskBlocks.length; i++) {
            if (!diskBlocks[i].isFree()) {
                if (diskBlocks[i].getObject() instanceof File) {
                    if (((File) (diskBlocks[i].getObject())).getLocation().equals(path)
                            && diskBlocks[i].isBegin()) {
                        bList.add(diskBlocks[i]);
                    }
                }
            }
        }
        return bList;
    }


    /**
     * 返回指定路径指向的文件夹
     * @param path
     * @return
     */
    public Folder getFolder(String path) {
        if (path.equals("C:")) {
            return c;
        }
        int split = path.lastIndexOf('\\');
        String location = path.substring(0, split);
        String folderName = path.substring(split + 1);
        List<Folder> folders = getFolders(location);
        for (Folder folder : folders) {
            if (folder.getFolderName().equals(folderName)) {
                return folder;
            }
        }
        return null;
    }
    /**
     * 返回指定路径下所有文件夹
     * @param path
     * @return
     */
    public List<Folder> getFolders(String path) {
        List<Folder> list = new ArrayList<Folder>();
        for (int i = 2; i < diskBlocks.length; i++) {
            if (!diskBlocks[i].isFree()) {
                if (diskBlocks[i].getObject() instanceof Folder) {
                    if (((Folder) (diskBlocks[i].getObject())).getLocation().equals(path)) {
                        list.add((Folder) diskBlocks[i].getObject());
                    }
                }
            }
        }
        return list;
    }
    /**
     * 判断指定盘块中的文件是否已打开
     * @param block
     * @return
     */
    public boolean isOpenedFile(DiskBlock block) {
        if (block.getObject() instanceof Folder) {
            return false;
        }
        return ((File) block.getObject()).isOpened();
    }
    public void addOpenedFile(DiskBlock block) {
        File thisFile = (File) block.getObject();
        openedFiles.add(thisFile);
        thisFile.setOpened(true);
    }
    /**
     * 判断指定路径下是否有同名文件夹或文件
     * @param path
     * @param name
     * @return
     */
    public boolean hasName(String path, String name) {
        Folder thisFolder = getFolder(path);
        for (Object child : thisFolder.getChildren()) {
            if(child instanceof Folder){
                Folder folder=(Folder)child;
                if(folder.getFolderName().equals(name)) return true;
            }else {
                File folder=(File)child;
                if(folder.getFileName().equals(name)) return true;
            }
        }
        return false;
    }
    /**
     * 给出路径名返回路径对象
     * @param path
     * @return
     */
    public Path getPath(String path) {
        for (Path p : paths) {
            if (p.getPathName().equals(path)) {
                return p;
            }
        }
        return null;
    }
    public void replacePath(Path oldPath, String newName) {
        oldPath.setPathName(newName);
    }
    public void removePath(Path path) {
        paths.remove(path);
        if (path.hasParent()) {
            path.getParent().removeChildren(path);
        }
    }
    /**
     * 删除
     * @param block
     * @return
     */
    public int delete(DiskBlock block) {
        if (block.getObject() instanceof File) {
            if (isOpenedFile(block)) {
                // 文件已打开，不能删除
                return 3;
            }
            File thisFile = (File) block.getObject();
            Folder parent = thisFile.getParent();
            if (parent instanceof Folder) {
                parent.removeChildren(thisFile);
                parent.setSize(FATUtil.getFolderSize(parent));
                while (parent.hasParent()) {
                    parent = parent.getParent();
                    parent.setSize(FATUtil.getFolderSize(parent));
                }
            }
            for (int i = 2; i < diskBlocks.length; i++) {
                if (!diskBlocks[i].isFree() && diskBlocks[i].getObject() instanceof File) {
                    System.out.println("yes");
                    if (((File) diskBlocks[i].getObject()).equals(thisFile)) {// 同一个对象
                        System.out.println("yes2");
                        diskBlocks[i].clearBlock();
                    }
                }
            }
            return 1;
        } else {
            String folderPath = ((Folder) block.getObject()).getLocation() + "\\"
                    + ((Folder) block.getObject()).getFolderName();
            int index = 0;
            for (int i = 2; i < diskBlocks.length; i++) {
                if (!diskBlocks[i].isFree()) {
                    Object obj = diskBlocks[i].getObject();
                    if (diskBlocks[i].getType().equals(FATUtil.FOLDER)) {
                        if (((Folder) obj).getLocation().equals(folderPath)) {
                            // 文件夹不为空，不能删除
                            return 2;
                        }
                    } else {
                        if (((File) obj).getLocation().equals(folderPath)) {
                            // 文件夹不为空，不能删除
                            return 2;
                        }
                    }
                    if (diskBlocks[i].getType().equals(FATUtil.FOLDER)) {
                        if (((Folder) diskBlocks[i].getObject()).equals(block.getObject())) {
                            index = i;
                        }
                    }
                }
            }
            Folder thisFolder = (Folder) block.getObject();
            Folder parent = thisFolder.getParent();
            if (parent instanceof Folder) {
                parent.removeChildren(thisFolder);
                parent.setSize(FATUtil.getFolderSize(parent));
            }
            paths.remove(getPath(folderPath));
            diskBlocks[index].clearBlock();
            return 0;
        }
    }
    /**
     * 文件长度变更时重新分配盘块
     * @param num
     * @param block
     * @return
     */
    public boolean reallocBlocks(int num, DiskBlock block) {
        File thisFile = (File) block.getObject();
        int begin = thisFile.getDiskNum();
        int index = diskBlocks[begin].getIndex();
        int oldNum = 1;
        while (index != FATUtil.END) {
            oldNum++;
            if (diskBlocks[index].getIndex() == FATUtil.END) {
                begin = index;
            }
            index = diskBlocks[index].getIndex();
        }

        if (num > oldNum) {
            // 增加磁盘块
            int n = num - oldNum;
            if (freeBlocksCount() < n) {
                // 超过磁盘容量
                return false;
            }
            int space = searchEmptyDiskBlock();
            diskBlocks[begin].setIndex(space);
            for (int i = 1; i <= n; i++) {
                space = searchEmptyDiskBlock();
                if (i == n) {
                    diskBlocks[space].allocBlock(FATUtil.END, FATUtil.FILE, thisFile, false);
                } else {
                    diskBlocks[space].allocBlock(FATUtil.END, FATUtil.FILE, thisFile, false);// 同一个文件的所有磁盘块拥有相同的对象
                    int space2 = searchEmptyDiskBlock();
                    diskBlocks[space].setIndex(space2);
                }
                System.out.println(thisFile);
            }
        } else if (num < oldNum) {
            // 减少磁盘块
            int end = thisFile.getDiskNum();
            while (num > 1) {
                end = diskBlocks[end].getIndex();
                num--;
            }
            int next = 0;
            for (int i = diskBlocks[end].getIndex(); i != FATUtil.END; i = next) {
                next = diskBlocks[i].getIndex();
                diskBlocks[i].clearBlock();
            }
            diskBlocks[end].setIndex(FATUtil.END);
        } else {
            // 不变
        }
        thisFile.setLength(num);
        return true;
    }
    public void removeOpenedFile(DiskBlock block) {
        File thisFile = (File) block.getObject();
        for (int i = 0; i < openedFiles.size(); i++) {
            if (openedFiles.get(i) == thisFile) {
                openedFiles.remove(i);
                thisFile.setOpened(false);
                break;
            }
        }
    }
    /**
     * 计算空闲盘块数
     * @return
     */
    public int freeBlocksCount() {
        int n = 0;
        for (int i = 2; i < diskBlocks.length; i++) {
            if (diskBlocks[i].isFree()) {
                n++;
            }
        }
        return n;
    }
    /**
     * 返回第一个空闲盘块的盘块号
     * @return
     */
    public int searchEmptyDiskBlock() {
        for (int i = 2; i < diskBlocks.length; i++) {
            if (diskBlocks[i].isFree()) {
                return i;
            }
        }
        return FATUtil.ERROR;
    }
}
